/*
 *  (c) 2010-2012 Ashwin Rayaprolu (http://swiftui.org)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 *  file except in compliance with the License. You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the
 *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 *  either express or implied. See the License for the specific language governing permissions
 *  and limitations under the License.
 */


if(typeof SwiftUI=='undefined') throw("LiveGridForms requires the SwiftUI JavaScript framework");


SwiftUI.TableEdit = function(liveGrid) {
  this.initialize(liveGrid);
}

SwiftUI.TableEdit.prototype = {
/**
 * @class Supports editing LiveGrid data.
 * @constructs
 */
  initialize: function(liveGrid) {
    SwiftUI.log('SwiftUI.TableEdit initialize: '+liveGrid.tableId);
    this.grid=liveGrid;
    this.options = {
      maxDisplayLen    : 20,    // max displayed text field length
      panelHeight      : 400,   // size of tabbed panels
      panelWidth       : 590,
      compact          : false,    // compact corners
      RecordName       : SwiftUI.getPhraseById("record"),
      updateURL        : window.location.href, // default is that updates post back to the generating page
      readOnlyColor    : '#AAA',   // read-only fields displayed using this color
      showSaveMsg      : 'errors'  // disposition of database update responses (full - show full response, errors - show full response for errors and short response otherwise)
    };
    SwiftUI.extend(this.options, liveGrid.options);
    this.hasWF2=(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('WebForms', '2.0'));
    this.menu=liveGrid.menu;
    this.menu.options.dataMenuHandler=SwiftUI.bind(this,'editMenu');
    this.menu.ignoreClicks();
    this.editText=SwiftUI.getPhraseById("editRecord",this.options.RecordName);
    this.cloneText=SwiftUI.getPhraseById("cloneRecord",this.options.RecordName);
    this.delText=SwiftUI.getPhraseById("deleteRecord",this.options.RecordName);
    this.addText=SwiftUI.getPhraseById("addRecord",this.options.RecordName);
    this.buttonHover=new SwiftUI.HoverSet();
    this.dateRegExp=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i;
    SwiftUI.EditControls.atLoad();
    this.createKeyArray();
    this.createEditDiv();
    this.saveMsg=SwiftUI.$(liveGrid.tableId+'_savemsg');
    SwiftUI.eventBind(document,"click", SwiftUI.eventHandle(this,'clearSaveMsg'));
    this.extraMenuItems=[];
    this.panelGroupCalled = "false";
    this.responseHandler=SwiftUI.bind(this,'processResponse');
    SwiftUI.log("SwiftUI.TableEdit.initialize complete, hasWF2="+this.hasWF2);
    
    //$(".ricoLG_editDiv > .ricoContent").css("overflow-y","auto");
    $(".Rico_tabContentContainer > .ui-widget-content").css("overflow-y","auto");
    $(".Rico_tabContentContainer > .ui-widget-content").css("height","300px");
     
  },

  createKeyArray: function() {
    this.keys=[];
    for (var i=0; i<this.grid.columns.length; i++) {
      if (this.grid.columns[i].format && this.grid.columns[i].format.isKey)
        this.keys.push({colidx:i});
    }
  },

  createEditDiv: function() {

    // create popup form

    this.requestCount=1;
    this.formPopup=new SwiftUI.Window('', {overflow: this.options.panels ? 'hidden' : 'auto'});
    this.formPopup.contentCell.className='ricoLG_editDiv';
    if (this.options.canEdit || this.options.canAdd) {
      this.startForm();
      this.createForm(this.form);
    } else {
      var buttonClose=this.createButton(SwiftUI.getPhraseById("close"));
      SwiftUI.eventBind(buttonClose,"click", SwiftUI.eventHandle(this,'cancelEdit'), false);
      this.createForm(this.formPopup.contentDiv);
    }
    this.editDivCreated=true;

    // create responseDialog

    this.responseDialog = this.grid.createDiv('editResponse',document.body);
    this.responseDialog.style.display='none';

    var buttonOK = document.createElement('button');
    buttonOK.appendChild(document.createTextNode('OK'));
    SwiftUI.eventBind(buttonOK,"click", SwiftUI.eventHandle(this,'ackResponse'));
    this.responseDialog.appendChild(buttonOK);

    this.responseDiv = this.grid.createDiv('editResponseText',this.responseDialog);

    if (this.panelGroup) {
      SwiftUI.log("createEditDiv complete, requestCount="+this.requestCount);
      SwiftUI.runLater(50,this,'initPanelGroup');
    }
  },

  initPanelGroup: function() {
    this.requestCount--;
    SwiftUI.log("initPanelGroup: "+this.requestCount);
    if (this.requestCount>0 || this.requestCount<0 ) {
    	return;
    }
    var wi=parseInt(this.options.panelWidth,10);
    if (this.form) {
      //this.form.style.width=(wi+10)+'px';
      if (SwiftUI.isWebKit) this.formPopup.container.style.display='block';  // this causes display to flash briefly
      this.options.bgColor = SwiftUI.Color.createColorFromBackground(this.form).toString();
    }
    this.formPopup.container.style.display='none';
    //this.options.panelHdrWidth=(Math.floor(wi / this.options.panels.length)-20)+'px';
    this.formPanels=new SwiftUI.TabbedPanel(this.panelGroup, this.options);
  },

  notEmpty: function(v) {
    return typeof(v)!='undefined';
  },

  startForm: function() {
    this.form = document.createElement('form');
    /** @ignore */
    this.form.onsubmit=function() {return false;};
    this.form.autocomplete="off"; // seems to fix "Permission denied..." errors in FF
    this.formPopup.contentDiv.appendChild(this.form);

    var tab = document.createElement('div');
    tab.className='ButtonBar';
    var button=tab.appendChild(this.createButton(SwiftUI.getPhraseById("saveRecord",this.options.RecordName)));
    SwiftUI.eventBind(button,"click", SwiftUI.eventHandle(this,'TESubmit'), false);
    button=tab.appendChild(this.createButton(SwiftUI.getPhraseById("cancel")));
    SwiftUI.eventBind(button,"click", SwiftUI.eventHandle(this,'cancelEdit'), false);
    this.form.appendChild(tab);

    // hidden fields
    this.hiddenFields = document.createElement('div');
    this.hiddenFields.style.display='none';
    this.action = this.appendHiddenField(this.grid.actionId,'');
    var i,fldSpec;
    for (i=0; i<this.grid.columns.length; i++) {
      fldSpec=this.grid.columns[i].format;
      if (fldSpec && fldSpec.FormView && fldSpec.FormView=="hidden")
        this.appendHiddenField(fldSpec.FieldName,fldSpec.ColData);
    }
    for (var k=0; k<this.keys.length; k++) {
      this.keys[k].keyField = this.appendHiddenField('_k'+this.keys[k].colidx,'');
    }
    this.form.appendChild(this.hiddenFields);
  },

  createButton: function(buttonLabel) {
    var button = document.createElement('a');
    button.href='javascript:void(0)';
    button.innerHTML=buttonLabel;
    button.className='RicoButton';
    if (SwiftUI.theme.button) SwiftUI.addClass(button,SwiftUI.theme.button);
    this.buttonHover.add(button);
    return button;
  },

  createPanel: function(i) {
    var hasFields=false;
    for (var j=0; j<this.grid.columns.length; j++) {
      var fldSpec=this.grid.columns[j].format;
      if (!fldSpec) continue;
      if (!fldSpec.EntryType) continue;
      if (fldSpec.EntryType=='H') continue;
      if (fldSpec.FormView && fldSpec.FormView=="hidden") continue;
      var panelIdx=fldSpec.panelIdx || 0;
      if (panelIdx==i) {
        hasFields=true;
        break;
      }
    }
    if (!hasFields) return null;
    this.panelHdr[i] = document.createElement('li');
    this.panelHdr[i].innerHTML=this.options.panels[i];
    this.panelHdrs.appendChild(this.panelHdr[i]);
    this.panelContent[i] = document.createElement('div');
    this.panelContents.appendChild(this.panelContent[i]);
    this.panelActualIdx[i]=this.panelCnt++;
    return this.createFormTable(this.panelContent[i],'tabContent');
  },

  createForm: function(parentDiv) {
    var i,div,fldSpec,panelIdx,tables=[];
    this.panelCnt=0;
    this.panelHdr=[];
    this.panelContent=[];
    if (this.options.panels) {
      this.panelGroup = document.createElement('div');
      this.panelGroup.className='tabPanelGroup';
      this.panelHdrs = document.createElement('ul');
      this.panelGroup.appendChild(this.panelHdrs);
      this.panelContents = document.createElement('div');
      this.panelContents.className='tabContentContainer';
      this.panelGroup.appendChild(this.panelContents);
      this.panelActualIdx=[];
      parentDiv.appendChild(this.panelGroup);
      if (this.grid.direction=='rtl') {
        for (i=this.options.panels.length-1; i>=0; i--) {
          tables[i]=this.createPanel(i);
        }
      } else {
        for (i=0; i<this.options.panels.length; i++) {
          tables[i]=this.createPanel(i);
        }
      }
      parentDiv.appendChild(this.panelGroup);
    } else {
      div=document.createElement('div');
      div.className='noTabContent';
      tables[0]=this.createFormTable(div);
      parentDiv.appendChild(div);
    }
    for (i=0; i<this.grid.columns.length; i++) {
      fldSpec=this.grid.columns[i].format;
      if (!fldSpec) continue;
      panelIdx=fldSpec.panelIdx || 0;
      if (tables[panelIdx]) this.appendFormField(this.grid.columns[i],tables[panelIdx]);
      if (typeof fldSpec.pattern=='string') {
        switch (fldSpec.pattern) {
          case 'email':
            fldSpec.regexp=/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$/;
            break;
          case 'float-unsigned':
            fldSpec.regexp=/^\d+(\.\d+)?$/;
            break;
          case 'float-signed':
            fldSpec.regexp=/^[-+]?\d+(\.\d+)?$/;
            break;
          case 'int-unsigned':
            fldSpec.regexp=/^\d+$/;
            break;
          case 'int-signed':
            fldSpec.regexp=/^[-+]?\d+$/;
            break;
          default:
            fldSpec.regexp=new RegExp(fldSpec.pattern);
            break;
        }
      }
    }
  },

  createFormTable: function(div) {
    var tab=document.createElement('table');
    tab.border=0;
    div.appendChild(tab);
    return tab;
  },

  appendHiddenField: function(name,value) {
    var field=SwiftUI.createFormField(this.hiddenFields,'input','hidden',name,name);
    field.value=value;
    return field;
  },

  appendFormField: function(column, table) {
    var fmt=column.format;
    if (!fmt.EntryType) return;
    if (fmt.EntryType=="H") return;
    if (fmt.FormView) return;
    SwiftUI.log('appendFormField: '+column.displayName+' - '+fmt.EntryType);
    var row = fmt.noFormBreak && table.rows.length > 0 ? table.rows[table.rows.length-1] : table.insertRow(-1);
    var hdr = row.insertCell(-1);
    column.formLabel=hdr;
    if (hdr.noWrap) hdr.noWrap=true;
    var entry = row.insertCell(-1);
    if (entry.noWrap) entry.noWrap=true;
    hdr.id='lbl_'+fmt.FieldName;
    var field, name=fmt.FieldName;
    switch (fmt.EntryType) {
      case 'TA':
      case 'tinyMCE':
        field=SwiftUI.createFormField(entry,'textarea',null,name);
        field.cols=parseInt(fmt.TxtAreaCols);
        field.rows=fmt.TxtAreaRows;
        field.innerHTML=fmt.ColData;
        hdr.style.verticalAlign='top';
        break;
      case 'R':
      case 'RL':
        field=SwiftUI.createFormField(entry,'div',null,name);
        if (fmt.DescriptionField) field.RicoUpdate=fmt.DescriptionField;
        if (fmt.MultiSelect) SwiftUI.addClass(field, 'MultiSelect');
        if (fmt.isNullable && !fmt.MultiSelect) this.addSelectNone(field);
        this.selectValuesRequest(field,column);
        break;
      case 'N':
        field=SwiftUI.createFormField(entry,'select',null,name);
        if (fmt.isNullable) this.addSelectNone(field);
        SwiftUI.eventBind(field,"change", SwiftUI.eventHandle(this,'checkSelectNew'));
        this.selectValuesRequest(field,column);
        field=document.createElement('span');
        field.className='ricoEditLabel';
        field.id='labelnew__'+fmt.FieldName;
        field.innerHTML='&nbsp;&nbsp;&nbsp;'+SwiftUI.getPhraseById('formNewValue').replace(' ','&nbsp;');
        entry.appendChild(field);
        name='textnew__'+fmt.FieldName;
        field=SwiftUI.createFormField(entry,'input','text',name,name);
        break;
      case 'S':
      case 'SL':
        if (fmt.ReadOnly) {
          field=SwiftUI.createFormField(entry,'input','text',name,name);
          this.initField(field,fmt);
        } else {
          field=SwiftUI.createFormField(entry,'select',null,name);
          if (fmt.MultiSelect) field.multiple=true;
          if (fmt.SelectRows) field.size=parseInt(fmt.SelectRows,10);
          if (fmt.isNullable && !fmt.MultiSelect) this.addSelectNone(field);
          if (fmt.InsertOnly) {
              SwiftUI.eventBind(field,"change", SwiftUI.eventHandle(this,'selectClickForInsert'), false);
              SwiftUI.eventBind(field,"focus", SwiftUI.eventHandle(this,'selectClickForFocus'), false);
          }
          if (fmt.DescriptionField) {
            field.RicoUpdate=fmt.DescriptionField;
            SwiftUI.eventBind(field,"change", SwiftUI.eventHandle(this,'selectClick'), false);
          }
          this.selectValuesRequest(field,column);
        }
        break;
      case 'CH':
          if (fmt.ReadOnly) {
            field=SwiftUI.createFormField(entry,'input','text',name,name);
            this.initField(field,fmt);
          } else {
            field=SwiftUI.createFormField(entry,'input','checkbox',name,name);
            if (fmt.DescriptionField) {
              field.RicoUpdate=fmt.DescriptionField;
              SwiftUI.eventBind(field,"change", SwiftUI.eventHandle(this,'checkBoxClick'), false);
              SwiftUI.eventBind(field, 'click', SwiftUI.eventHandle(this,'checkBoxClick')); 
            }
          }
          break;        
      case 'D':
        if (!fmt.isNullable) fmt.required=true;
        if (!fmt.dateFmt) fmt.dateFmt=SwiftUI.dateFmt;
        if (!fmt.Help) fmt.Help=fmt.dateFmt;
        if (typeof fmt.min=='string') fmt.min=SwiftUI.setISO8601(fmt.min) || new Date(fmt.min);
        if (typeof fmt.max=='string') fmt.max=SwiftUI.setISO8601(fmt.max) || new Date(fmt.max);
        if (this.hasWF2) {
          field=SwiftUI.createFormField(entry,'input','date',name,name);
          field.required=fmt.required;
          if (fmt.min) field.min=SwiftUI.toISO8601String(fmt.min,3);
          if (fmt.max) field.max=SwiftUI.toISO8601String(fmt.max,3);
          field.required=fmt.required;
          fmt.SelectCtl=null;  // use the WebForms calendar instead of the Rico calendar
        } else {
          field=SwiftUI.createFormField(entry,'input','text',name,name);
        }
        this.initField(field,fmt);
        break;
      case 'I':
        if (!fmt.isNullable) fmt.required=true;
        if (!fmt.pattern) fmt.pattern='int-signed';
        if (this.hasWF2) {
          field=SwiftUI.createFormField(entry,'input','number',name,name);
          field.required=fmt.required;
          field.min=fmt.min;
          field.max=fmt.max;
          field.step=1;
        } else {
          field=SwiftUI.createFormField(entry,'input','text',name,name);
        }
        if (typeof fmt.min=='string') fmt.min=parseInt(fmt.min,10);
        if (typeof fmt.max=='string') fmt.max=parseInt(fmt.max,10);
        this.initField(field,fmt);
        break;
      case 'F':
        if (!fmt.isNullable) fmt.required=true;
        if (!fmt.pattern) fmt.pattern='float-signed';
        field=SwiftUI.createFormField(entry,'input','text',name,name);
        this.initField(field,fmt);
        if (typeof fmt.min=='string') fmt.min=parseFloat(fmt.min);
        if (typeof fmt.max=='string') fmt.max=parseFloat(fmt.max);
        break;
      default:
        field=SwiftUI.createFormField(entry,'input','text',name,name);
        if (!fmt.isNullable && fmt.EntryType!='T') fmt.required=true;
        this.initField(field,fmt);
        break;
    }
    if (field) {
      if (fmt.SelectCtl)
        SwiftUI.EditControls.applyTo(column,field);
    }
    var hdrSuffix='';
    hdr.className='ricoEditLabel';
    if (fmt.Help) {
      hdr.title=fmt.Help;
      hdrSuffix="&nbsp;<img src='"+SwiftUI.imgDir+"info_icon.gif'>";
      SwiftUI.addClass(hdr,'ricoHelp');
    }
    var hdrText=fmt.EntryType.length>1 && fmt.EntryType.charAt(1)=='L' ? column.next.displayName : column.displayName;
    hdr.innerHTML=hdrText+hdrSuffix;
  },

  addSelectNone: function(field) {
    this.addSelectOption(field,this.options.TableSelectNone,SwiftUI.getPhraseById("selectNone"));
  },

  initField: function(field,fmt) {
    if (fmt.Length) {
      field.maxLength=fmt.Length;
      field.size=Math.min(fmt.Length, this.options.maxDisplayLen);
    }
    field.value=fmt.ColData;
  },
  
  selectClick: function(e) {
    var SelObj=SwiftUI.eventElement(e);
    if (SelObj.readOnly) {
      SwiftUI.eventStop(e);
      return false;
    }
    if (SelObj.RicoUpdate) {
      var opt=SelObj.options[SelObj.selectedIndex];
      SwiftUI.$(SelObj.RicoUpdate).value=opt.innerHTML;
    }
  },
  
  selectClickForFocus:function(e){
	  var SelObj=SwiftUI.eventElement(e);
	    if (SelObj.readOnly) {
	    	SelObj.defaultIndex = SelObj.selectedIndex;
	    	return false;
	    }
  },
  
  selectClickForInsert: function(e){
	  var SelObj=SwiftUI.eventElement(e);
	    if (SelObj.readOnly) {
	    	SwiftUI.eventStop(e);
	    	SelObj.selectedIndex = SelObj.defaultIndex;
	    	return false;
	    }
  },
  
  checkBoxClick: function(e) {
	    var SelObj=SwiftUI.eventElement(e);
	    if (SelObj.readOnly) {
	    	SwiftUI.eventStop(e);
	    	return false;
	    }
	    if (SelObj.RicoUpdate) {
	    	 var newval=SelObj.checked ? SelObj._checkedValue : SelObj._uncheckedValue;
	    	 SwiftUI.$(SelObj.RicoUpdate).value=newval;
	    }
	    SwiftUI.eventStop(e);   
  },  
  
  radioClick: function(e) {
    var ChkBoxObj=SwiftUI.eventElement(e);
    if (ChkBoxObj.readOnly) {
      SwiftUI.eventStop(e);
      return false;
    }
    var container=SwiftUI.getParentByTagName(ChkBoxObj,'div');
    if (container.RicoUpdate) {
      SwiftUI.$(container.RicoUpdate).value=ChkBoxObj.nextSibling.innerHTML;
    }
  },

  checkSelectNew: function(e) {
    this.updateSelectNew(SwiftUI.eventElement(e));
  },

  updateSelectNew: function(SelObj) {
    var vis=(SelObj.value==this.options.TableSelectNew) ? "" : "hidden";
    SwiftUI.$("labelnew__" + SelObj.id).style.visibility=vis;
    SwiftUI.$("textnew__" + SelObj.id).style.visibility=vis;
  },

  selectValuesRequest: function(elem,column) {
    var fldSpec=column.format;
    if (fldSpec.SelectValues) {
      var valueList=fldSpec.SelectValues.split(',');
      for (var i=0; i<valueList.length; i++)
        this.addSelectOption(elem,valueList[i],valueList[i],i);
    } else {
      var options={};
      SwiftUI.extend(options, this.grid.buffer.ajaxOptions);
      options.parameters = {id: this.grid.tableId, offset: '0', page_size: '-1', edit: column.index};
      options.parameters[this.grid.actionId]="query";
      options.onComplete = SwiftUI.bind(this,'selectValuesUpdate',elem);
      options.onSuccess = SwiftUI.bind(this,'selectValuesUpdate',elem);
      options.onFailure = SwiftUI.bind(this,'selectValuesUpdate',elem);
      new SwiftUI.ajaxRequest(this.grid.buffer.dataSource, options);
      this.requestCount++;
      SwiftUI.log("selectValuesRequest: "+fldSpec.FieldName);
    }
  },

  selectValuesUpdate: function(elem,request) {
	    var response = "";
	    try{
	    	response = request.responseXML.getElementsByTagName("ajax-response");
	    }catch(error){
	    	alert(error);
	    }
    SwiftUI.log("selectValuesUpdate: "+request.status);
    if (response == null || response.length != 1) return;
    response=response[0];
    var error = response.getElementsByTagName('error');
    if (error.length > 0) {
      var errmsg=SwiftUI.getContentAsString(error[0],this.grid.buffer.isEncoded);
      SwiftUI.log("Data provider returned an error:\n"+errmsg);
      alert(SwiftUI.getPhraseById("requestError",errmsg));
      return null;
    }
    response=response.getElementsByTagName('response')[0];
    var rowsElement = response.getElementsByTagName('rows')[0];
    var rows = this.grid.buffer.dom2jstable(rowsElement);
    SwiftUI.log("selectValuesUpdate: id="+elem.id+' rows='+rows.length);
    for (var i=0; i<rows.length; i++) {
      if (rows[i].length>0) {
        var c0=rows[i][0];
        var c1=(rows[i].length>1) ? rows[i][1] : c0;
        this.addSelectOption(elem,c0,c1,i);
      }
    }
    if (SwiftUI.$('textnew__'+elem.id))
      this.addSelectOption(elem,this.options.TableSelectNew,SwiftUI.getPhraseById("selectNewVal"));
    
    // Small hack for now
    if(this.requestCount > 3)
    	this.requestCount = 1;
    
    if (this.panelGroup)
      SwiftUI.runLater(50,this,'initPanelGroup');
  },

  addSelectOption: function(elem,value,text,idx) {
    switch (elem.tagName.toLowerCase()) {
      case 'div':
        var opt=SwiftUI.createFormField(elem,'input', SwiftUI.hasClass(elem, 'MultiSelect') ? 'checkbox' : 'radio', elem.id+'_'+idx, elem.id);
        opt.value=value;
        var lbl=document.createElement('label');
        lbl.innerHTML=text;
        lbl.htmlFor=opt.id;
        elem.appendChild(lbl);
        SwiftUI.eventBind(opt,"click", SwiftUI.eventHandle(this,'radioClick'), false);
        break;
      case 'select':
        SwiftUI.addSelectOption(elem,value,text);
        break;
    }
  },

  clearSaveMsg: function() {
    if (this.saveMsg) this.saveMsg.innerHTML="";
  },

  addMenuItem: function(menuText,menuAction,enabled) {
    this.extraMenuItems.push({menuText:menuText,menuAction:menuAction,enabled:enabled});
  },

  editMenu: function(grid,r,c,onBlankRow) {
    this.clearSaveMsg();
    if (this.grid.buffer.sessionExpired==true || this.grid.buffer.startPos<0) return false;
    this.rowIdx=r;
    var elemTitle=SwiftUI.$('pageTitle');
    var pageTitle=elemTitle ? elemTitle.innerHTML : document.title;
    this.menu.addMenuHeading(pageTitle);
    if (onBlankRow==false) {
      for (var i=0; i<this.extraMenuItems.length; i++) {
        this.menu.addMenuItem(this.extraMenuItems[i].menuText,this.extraMenuItems[i].menuAction,this.extraMenuItems[i].enabled);
      }
      this.menu.addMenuItem(this.editText,SwiftUI.bind(this,'editRecord'),this.canEdit(r));
      this.menu.addMenuItem(this.delText,SwiftUI.bind(this,'deleteRecord'),this.canDelete(r));
      if (this.options.canClone) {
        this.menu.addMenuItem(this.cloneText,SwiftUI.bind(this,'cloneRecord'),this.canAdd(r) && this.canEdit(r));
      }
    }
    this.menu.addMenuItem(this.addText,SwiftUI.bind(this,'addRecord'),this.canAdd(r));
    return true;
  },
  
  canAdd: function(r) {
    return (typeof this.options.canAdd=='function') ? this.options.canAdd(r) : this.options.canAdd;
  },

  canEdit: function(r) {
    return (typeof this.options.canEdit=='function') ? this.options.canEdit(r) : this.options.canEdit;
  },

  canDelete: function(r) {
    return (typeof this.options.canDelete=='function') ? this.options.canDelete(r) : this.options.canDelete;
  },

  cancelEdit: function(e) {
    SwiftUI.eventStop(e);
    for (var i=0; i<this.grid.columns.length; i++) {
      if (this.grid.columns[i].format && this.grid.columns[i].format.SelectCtl)
        SwiftUI.EditControls.close(this.grid.columns[i].format.SelectCtl);
    }
    this.makeFormInvisible();
    this.grid.highlightEnabled=true;
    this.menu.cancelmenu();
    return false;
  },

  setField: function(fldnum,fldvalue) {
    var fldSpec=this.grid.columns[fldnum].format;
    var e=SwiftUI.$(fldSpec.FieldName);
    var a,i,o,elems,opts,txt;
    if (!e) return;
    SwiftUI.log('setField: '+fldSpec.FieldName+'='+fldvalue);
    switch (e.tagName.toUpperCase()) {
      case 'DIV':
        elems=e.getElementsByTagName('INPUT');
        o={}
        if (fldSpec.MultiSelect && fldvalue) {
          a=fldvalue.split(',');
          for (var i=0; i<a.length; i++) o[a[i]]=1;
        } else {
          o[fldvalue]=1;
        }
        for (i=0; i<elems.length; i++)
          elems[i].checked=o[elems[i].value]==1;
        break;
      case 'INPUT':
        if (fldSpec.EntryType=='D' && fldvalue!=fldSpec.ColData) {
          // remove time data if it exists
          a=fldvalue.split(/\s|T/);
          fldvalue=a[0];
          if (this.isTextInput(e)) {
            var d=SwiftUI.setISO8601(fldvalue);
            if (d) fldvalue=SwiftUI.formatDate(d,fldSpec.dateFmt);
          }
        }else if (fldSpec.EntryType=='CH' && fldvalue!=fldSpec.ColData) {
            if(fldvalue == 'true'){
            	e.checked=true;
            }else{
            	e.checked=false;
            }
            break;
        }
       	e.value=fldvalue;
        break;
      case 'SELECT':
        opts=e.options;
        //alert('setField SELECT: id='+e.id+'\nvalue='+fldvalue+'\nopt cnt='+opts.length)
        o={}
        if (fldSpec.MultiSelect && fldvalue) {
          a=fldvalue.split(',');
          for (var i=0; i<a.length; i++) o[a[i]]=1;
          for (i=0; i<opts.length; i++)
            opts[i].selected=o[opts[i].value]==1;
        } else {
          for (i=0; i<opts.length; i++) {
            if (opts[i].value==fldvalue) {
              e.selectedIndex=i;
              break;
            }
          }
        }
        if (fldSpec.EntryType=='N') {
          txt=SwiftUI.$('textnew__'+e.id);
          if (!txt) alert('Warning: unable to find id "textnew__'+e.id+'"');
          txt.value=fldvalue;
          if (e.selectedIndex!=i) e.selectedIndex=opts.length-1;
          this.updateSelectNew(e);
        }
        return;
      case 'TEXTAREA':
        e.value=fldvalue;
        if (fldSpec.EntryType=='tinyMCE' && typeof(tinyMCE)!='undefined' && this.initialized) {
          if (tinyMCE.updateContent) {
            tinyMCE.updateContent(e.id);  // version 2.x
          } else {
            tinyMCE.execInstanceCommand(e.id, 'mceSetContent', false, fldvalue);  // version 3.x
          }
        }
        return;
    }
  },

  setReadOnly: function(addFlag) {
    for (var i=0; i<this.grid.columns.length; i++) {
      var fldSpec=this.grid.columns[i].format;
      if (!fldSpec) continue;
      var e=SwiftUI.$(fldSpec.FieldName);
      if (!e) continue;
      var ro=!fldSpec.Writeable || fldSpec.ReadOnly || (fldSpec.InsertOnly && !addFlag) || (fldSpec.UpdateOnly && addFlag);
      var color=ro ? this.options.readOnlyColor : '';
      switch (e.tagName.toUpperCase()) {
        case 'DIV':
          e.style.color=color;
          var elems=e.getElementsByTagName('INPUT');
          for (var j=0; j<elems.length; j++) {
            elems[j].readOnly=ro;
          }
          break;
        case 'SELECT':
          if (fldSpec.EntryType=='N') {
            var txt=SwiftUI.$('textnew__'+e.id);
            txt.readOnly=ro;
          }
          if(ro == 'true' || ro == true){
        	  e.onfocus="this.defaultIndex=this.selectedIndex;";
        	  e.onchange="this.selectedIndex=this.defaultIndex;";
          }
          // onfocus="this.defaultIndex=this.selectedIndex;" onchange="this.selectedIndex=this.defaultIndex;"
          e.readOnly=ro;
          break;
        case 'TEXTAREA':
        case 'INPUT':
          e.readOnly=ro;
          e.style.color=color;
          if (fldSpec.selectIcon) fldSpec.selectIcon.style.display=ro ? 'none' : '';
          break;
      }
    }
  },

  hideResponse: function(msg) {
    this.responseDiv.innerHTML=msg;
    this.responseDialog.style.display='none';
  },

  showResponse: function() {
    var offset=SwiftUI.cumulativeOffset(this.grid.outerDiv);
    offset.top+=SwiftUI.docScrollTop();
    this.responseDialog.style.top=offset.top+"px";
    this.responseDialog.style.left=offset.left+"px";
    this.responseDialog.style.display='';
  },

  processResponse: function(xhr) {
    var responseText,success=true;
    SwiftUI.log('Processing response from form submittal');
    this.responseDiv.innerHTML=xhr.responseText;
    var respNodes=SwiftUI.select('.ricoFormResponse',this.responseDiv);
    if (respNodes && respNodes.length > 0) {
      // generate a translated response
    	try{
		      var phraseId=SwiftUI.trim(respNodes[0].className).split(/\s+/)[1];
		      responseText=SwiftUI.getPhraseById(phraseId,this.options.RecordName);
    	}catch(e){
    		responseText = "";
    	}
    } else {
      // present the response as sent from the server (untranslated)
      var ch=this.responseDiv.childNodes;
      for (var i=ch.length-1; i>=0; i--) {
        if (ch[i].nodeType==1 && ch[i].nodeName!='P' && ch[i].nodeName!='DIV' && ch[i].nodeName!='BR')
          this.responseDiv.removeChild(ch[i]);
      }
      responseText=SwiftUI.stripTags(this.responseDiv.innerHTML);
      success=(responseText.toLowerCase().indexOf('error')==-1);
    }
    if (success && this.options.showSaveMsg!='full') {
      this.hideResponse('');
      this.grid.resetContents();
      this.grid.buffer.foundRowCount = false;
      this.grid.buffer.fetch(this.grid.lastRowPos || 0);
      if (this.saveMsg) this.saveMsg.innerHTML='&nbsp;'+responseText+'&nbsp;';
    }
    this.processCallback(this.options.onSubmitResponse);
    SwiftUI.log('Processing response completed');
  },

  processCallback: function(callback) {
    switch (typeof callback) {
      case 'string': return eval(callback);
      case 'function': return callback();
    }
  },

  // called when ok pressed on error response message
  ackResponse: function(e) {
    this.hideResponse('');
    this.grid.highlightEnabled=true;
  },

  cloneRecord: function() {
    this.formPopup.setTitle(this.cloneText);
    this.displayEditForm("ins");
  },

  editRecord: function() {
    this.formPopup.setTitle(this.editText);
    this.displayEditForm("upd");
  },

  displayEditForm: function(action) {
    this.grid.highlightEnabled=false;
    this.menu.cancelmenu();
    this.hideResponse(SwiftUI.getPhraseById('saving'));
    this.grid.outerDiv.style.cursor = 'auto';
    this.action.value=action;
    for (var i=0; i<this.grid.columns.length; i++) {
      var c=this.grid.columns[i];
      if (c.format) {
        var v=c.getValue(this.rowIdx);
        this.setField(i,v);
        if (c.format.selectDesc) {
          if (c.format.EntryType.length>1 && c.format.EntryType.charAt(1)=='L')
            v=this.grid.columns[i+1].getValue(this.rowIdx);
          v=c._format(v);
          if (v==='') v='&nbsp;';
          c.format.selectDesc.innerHTML=v;
        }
        if (c.format.SelectCtl)
          SwiftUI.EditControls.displayClrImg(c, !c.format.InsertOnly);
      }
    }
    this.setReadOnly(action=='ins');
    for (var k=0; k<this.keys.length; k++) {
      this.keys[k].keyField.value = this.grid.buffer.getWindowValue(this.rowIdx,this.keys[k].colidx);
    }
    this.makeFormVisible(this.rowIdx);
  },
  
  addPrepare: function() {
    this.hideResponse(SwiftUI.getPhraseById('saving'));
    this.setReadOnly(true);
    this.form.reset();
    this.action.value="ins";
    for (var i=0; i<this.grid.columns.length; i++) {
      var c=this.grid.columns[i];
      if (c.format) {
        this.setField(i,c.format.ColData);
        if (c.format.SelectCtl) {
          SwiftUI.EditControls.resetValue(c);
          SwiftUI.EditControls.displayClrImg(c, !c.format.UpdateOnly);
        }
      }
    }
  },

  addRecord: function() {
    this.menu.cancelmenu();
    this.formPopup.setTitle(this.addText);
    this.addPrepare();
    this.makeFormVisible(-1);
    if (this.formPanels) this.formPanels.select(0);
  },

  drillDown: function(e,masterColNum,detailColNum) {
    return this.grid.drillDown.apply(this.grid, arguments);
  },

  // set filter on a detail grid that is in a master-detail relationship
  setDetailFilter: function(colNumber,filterValue) {
    this.grid.setDetailFilter(colNumber,filterValue);
  },

  makeFormVisible: function(row) {
    this.formPopup.container.style.display='block';

    // set left position
    var editWi=this.formPopup.container.offsetWidth;
    var odOffset=SwiftUI.cumulativeOffset(this.grid.outerDiv);
    var winWi=SwiftUI.windowWidth();
    this.formPopup.container.style.left=editWi+odOffset.left > winWi ? (winWi-editWi)+'px' : (odOffset.left+1)+'px';

    // set top position
    var scrTop=SwiftUI.docScrollTop();
    var editHt=this.formPopup.container.offsetHeight;
    var newTop=odOffset.top+this.grid.hdrHt+scrTop;
    var bottom=SwiftUI.windowHeight()+scrTop;
    if (row >= 0) {
      newTop+=(row+1)*this.grid.rowHeight;
      if (newTop+editHt>bottom) newTop-=(this.formPopup.contentCell.offsetHeight+this.grid.rowHeight);
    } else {
      if (newTop+editHt>bottom) newTop=bottom-editHt-2;
    }

    // By Ashwin
    newTop = 120;
    
    
    if (this.processCallback(this.options.formOpen) === false) return;
    this.formPopup.openPopup(null,Math.max(newTop,scrTop));
    this.formPopup.container.style.visibility='visible';
    SwiftUI.EditControls.setZ(SwiftUI.getStyle(this.formPopup.container,'zIndex'));
    if (this.initialized) return;

    var i, spec;
    for (i = 0; i < this.grid.columns.length; i++) {
      spec=this.grid.columns[i].format;
      if (!spec || !spec.EntryType || !spec.FieldName) continue;
      switch (spec.EntryType) {
        case 'tinyMCE':
          if (typeof tinyMCE!='undefined') tinyMCE.execCommand('mceAddControl', true, spec.FieldName);
          break;
      }
    }
    this.initialized=true;
  },

  makeFormInvisible: function() {
    this.formPopup.container.style.visibility='hidden';
    this.formPopup.closePopup();
    this.processCallback(this.options.formClose);
  },

  getConfirmDesc: function(rowIdx) {
    return SwiftUI.stripTags(this.grid.cell(rowIdx,this.options.ConfirmDeleteCol).innerHTML).replace('&nbsp;',' '); //.unescapeHTML();
  },

  deleteRecord: function() {
    this.menu.cancelmenu();
    var desc;
    switch(this.options.ConfirmDeleteCol){
      case -1 :
        desc=SwiftUI.getPhraseById("thisRecord",this.options.RecordName);
        break;
      case -2 : // Use key/column header to identify the row
        for (var k=0; k<this.keys.length; k++) {
          var i=this.keys[k].colidx;
          var fmt=this.grid.columns[i].format;
          if (fmt.EntryType.length>1 && fmt.EntryType.charAt(1)=='L') i++;
          var value=SwiftUI.stripTags(this.grid.cell(rowIdx,i).innerHTML);
          if (desc) desc+=', ';
          desc+=this.grid.columns[i].displayName+" "+value;
        }
        break;
      default   :
        desc='\"' + SwiftUI.truncate(this.getConfirmDesc(this.rowIdx),50) + '\"';
        break;
    }
    if (!this.options.ConfirmDelete.valueOf || confirm(SwiftUI.getPhraseById("confirmDelete",desc))) {
      this.hideResponse(SwiftUI.getPhraseById('deleting'));
      this.showResponse();
      var parms={};
      parms[this.grid.actionId]="del";
      for (var k=0; k<this.keys.length; k++) {
        var i=this.keys[k].colidx;
        var value=this.grid.columns[i].getValue(this.rowIdx);
        parms['_k'+i]=value;  // prototype does the encoding automatically
        //parms['_k'+i]=encodeURIComponent(value);
      }
      new SwiftUI.ajaxRequest(this.options.updateURL, {parameters:parms,method:'post',onComplete:this.responseHandler});
    }
    this.menu.cancelmenu();
  },

  validationMsg: function(elem,colnum,phraseId) {
    var col=this.grid.columns[colnum];
    if (this.formPanels) this.formPanels.select(this.panelActualIdx[col.format.panelIdx]);
    var msg=SwiftUI.getPhraseById(phraseId," \"" + col.formLabel.innerHTML + "\"");
    SwiftUI.log(' Validation error: '+msg);
    if (col.format.Help) msg+="\n\n"+col.format.Help;
    alert(msg);
    setTimeout(function() { try { elem.focus(); elem.select(); } catch(e) {}; }, 10);
    return false;
  },
  
  isTextInput: function(elem) {
    if (!elem) return false;
    if (elem.tagName.toLowerCase()!='input') return false;
    if (elem.type.toLowerCase()!='text') return false;
    if (elem.readOnly) return false;
    if (!SwiftUI.visible(elem)) return false;
    return true;
  },
  
  parseDate: function(v, dateFmt) {
    dateParts={};
    if (!this.dateRegExp.exec(dateFmt)) return NaN;
    dateParts[RegExp.$1]=0;
    dateParts[RegExp.$3]=1;
    dateParts[RegExp.$5]=2;
    var aDate = v.split(/\D/);
    var d=new Date();
    var curyr=d.getFullYear();
    if (aDate.length==2 && dateParts.yyyy==2) aDate.push(curyr);
    if (aDate.length!=3) return NaN;
    var dd=parseInt(aDate[dateParts.dd], 10);
    if (dd==0 || dd>31) return NaN;
    var mm=parseInt(aDate[dateParts.mm], 10) - 1;
    if (mm > 11) return NaN;
    var yy=parseInt(aDate[dateParts.yyyy], 10);
    if (yy < 100) {
      // apply a century to 2-digit years
      yy+=curyr - (curyr % 100);
    }
    d.setFullYear(yy,mm,dd);
    return d;
  },

  TESubmit: function(e) {
    var i,lbl,spec,elem,n,dateValues=[];

    SwiftUI.eventStop(e);
    SwiftUI.log('Event: TESubmit called to validate input');

    // check fields that are supposed to be non-blank

    for (i = 0; i < this.grid.columns.length; i++) {
      spec=this.grid.columns[i].format;
      if (!spec || !spec.EntryType || !spec.FieldName) continue;
      elem=SwiftUI.$(spec.FieldName);
      if (!this.isTextInput(elem)) continue;
      SwiftUI.log(' Validating field #'+i+' EntryType='+spec.EntryType+' ('+spec.FieldName+')');

      // check for blanks
      if (elem.value.length == 0) {
        if (spec.required)
          return this.validationMsg(elem,i,"formPleaseEnter");
        else
          continue;
      }

      // check pattern
      if (elem.value.length > 0 && spec.regexp && !spec.regexp.test(elem.value))
        return this.validationMsg(elem,i,"formInvalidFmt");

      // check min/max and date values
      switch (spec.EntryType.charAt(0)) {
        case 'I': n=parseInt(elem.value,10); break;
        case 'F': n=parseFloat(elem.value); break;
        case 'D': 
          n=this.parseDate(elem.value,spec.dateFmt);
          if (isNaN(n)) return this.validationMsg(elem,i,"formInvalidFmt");
          dateValues.push({e:elem,v:n});
          break;
        default:  n=NaN; break;
      }
      if (typeof spec.min!='undefined' && !isNaN(n) && n < spec.min)
        return this.validationMsg(elem,i,"formOutOfRange");
      if (typeof spec.max!='undefined' && !isNaN(n) && n > spec.max)
        return this.validationMsg(elem,i,"formOutOfRange");
    }
    if (this.processCallback(this.options.formSubmit) === false) return false;

    // update drop-down for any columns with entry type of N

    for (i = 0; i < this.grid.columns.length; i++) {
      spec=this.grid.columns[i].format;
      if (!spec || !spec.EntryType || !spec.FieldName) continue;
      if (spec.EntryType.charAt(0) != 'N') continue;
      var SelObj=SwiftUI.$(spec.FieldName);
      if (!SelObj || SelObj.value!=this.options.TableSelectNew) continue;
      var newtext=SwiftUI.$("textnew__" + SelObj.id).value;
      this.addSelectOption(SelObj,newtext,newtext);
    }
    
    // set date values to ISO format
    for (i = 0; i < dateValues.length; i++) {
      dateValues[i].e.value = SwiftUI.formatDate(dateValues[i].v,'yyyy-mm-dd');
    }

    if (typeof tinyMCE!='undefined') tinyMCE.triggerSave();
    this.makeFormInvisible();
    this.sendForm();
    this.menu.cancelmenu();
    return false;
  },
  
  sendForm: function() {
    this.showResponse();
    SwiftUI.log("sendForm: "+this.grid.tableId);
    SwiftUI.ajaxSubmit(this.form, this.options.updateURL, {method:'post',onComplete:this.responseHandler});
  }
};


/**
 * @namespace Registers custom popup widgets to fill in a text box (e.g. ricoCalendar and ricoTree)
 * <pre>
 * Custom widget must implement:
 *   open() method (make control visible)
 *   close() method (hide control)
 *   container property (div element that contains the control)
 *   id property (uniquely identifies the widget class)
 *
 * widget calls returnValue method to return a value to the caller
 *
 * this object handles clicks on the control's icon and positions the control appropriately.
 * </pre>
 */
SwiftUI.EditControls = {
  widgetList : {},
  elemList   : {},
  zIndex     : 0,

  register: function(widget, imgsrc) {
    this.widgetList[widget.id] = {imgsrc:imgsrc, widget:widget, currentEl:''};
    widget.returnValue=SwiftUI.bind(this,'setValue',widget);
    SwiftUI.log("SwiftUI.EditControls.register:"+widget.id);
  },
  
  setZ: function(z) {
    this.zIndex=Math.max(this.zIndex,z+10);
  },

  atLoad: function() {
    for (var id in this.widgetList) {
      var widget=this.widgetList[id].widget;
      if (widget.atLoad && !widget.atLoadComplete) {
        SwiftUI.log("SwiftUI.EditControls.atLoad: "+id);
        widget.atLoad();
        widget.atLoadComplete=true;
      }
    }
  },

  applyTo: function(column,inputCtl) {
    var wInfo=this.widgetList[column.format.SelectCtl];
    if (!wInfo) return;
    SwiftUI.log('SwiftUI.EditControls.applyTo: '+column.displayName+' : '+column.format.SelectCtl);
    var descSpan = document.createElement('span');
    var newimg = document.createElement('img');
    newimg.style.paddingLeft='4px';
    newimg.style.cursor='pointer';
    newimg.align='top';
    newimg.src=wInfo.imgsrc;
    newimg.id=this.imgId(column.format.FieldName);
    SwiftUI.eventBind(newimg,"click", SwiftUI.eventHandle(this,'processClick'));
    inputCtl.parentNode.appendChild(descSpan);
    inputCtl.parentNode.appendChild(newimg);
    inputCtl.style.display='none';    // comment out this line for debugging
    var clr;
    if (column.format.isNullable) {
      clr=SwiftUI.clearButton(SwiftUI.eventHandle(this,'processClear'));
      clr.id=newimg.id+'_clear';
      inputCtl.parentNode.appendChild(clr);
    }
    this.elemList[newimg.id] = {descSpan:descSpan, inputCtl:inputCtl, widget:wInfo.widget, listObj:wInfo, column:column, clrimg:clr};
    column.format.selectIcon=newimg;
    column.format.selectDesc=descSpan;
  },

  displayClrImg: function(column,bShow) {
    var el=this.elemList[this.imgId(column.format.FieldName)];
    //alert(column.format.FieldName+': '+bShow+' '+typeof(el.clrimg));
    if (el && el.clrimg) el.clrimg.style.display=bShow ? 'inline-block' : 'none';
  },

  processClear: function(e) {
    var elem=SwiftUI.eventElement(e);
    var el=this.elemList[elem.id.slice(0,-6)];
    if (!el) return;
    el.inputCtl.value='';
    el.descSpan.innerHTML=el.column._format('');
  },

  processClick: function(e) {
    var elem=SwiftUI.eventElement(e);
    var el=this.elemList[elem.id];
    if (!el) return;
    if (el.listObj.currentEl==elem.id && el.widget.container.style.display!='none') {
      el.widget.close();
      el.listObj.currentEl='';
    } else {
      el.listObj.currentEl=elem.id;
      SwiftUI.log('SwiftUI.EditControls.processClick: '+el.widget.id+' : '+el.inputCtl.value);
      el.widget.container.style.zIndex=this.zIndex;
      el.widget.open(el.inputCtl.value,el.column);     // this may change the size of the widget
      SwiftUI.positionCtlOverIcon(el.widget.container,elem);
    }
  },

  imgId: function(fieldname) {
    return 'icon_'+fieldname;
  },

  resetValue: function(column) {
    var el=this.elemList[this.imgId(column.format.FieldName)];
    if (!el) return;
    el.inputCtl.value=column.format.ColData;
    var v=column._format(column.format.ColData);
    if (v==='') v='&nbsp;';
    el.descSpan.innerHTML=v;
  },

  setValue: function(widget,newVal,newDesc) {
    var wInfo=this.widgetList[widget.id];
    if (!wInfo) return null;
    var id=wInfo.currentEl;
    if (!id) return null;
    var el=this.elemList[id];
    if (!el) return null;
    el.inputCtl.value=newVal;
    if (!newDesc) newDesc=el.column._format(newVal);
    el.descSpan.innerHTML=newDesc;
    if (el.column.format.DescriptionField)
      SwiftUI.$(el.column.format.DescriptionField).value = newDesc;
    //alert(widget.id+':'+id+':'+el.inputCtl.id+':'+el.inputCtl.value+':'+newDesc);
  },

  close: function(id) {
    var wInfo=this.widgetList[id];
    if (!wInfo) return;
    if (wInfo.widget.container.style.display!='none')
      wInfo.widget.close();
  }
};

SwiftUI.includeLoaded('SwiftUIGenericForms.js');
